
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>
#include <malloc.h>
#include <sstream>
#include "define.h"
#include "Debug.h"
#include "SocketConn.h"
#include "NantSock.h"

using namespace netproxy;
using namespace std;

bool SocketConn::Connect( )
{
        m_lCurtime = time(NULL);
	if(m_socket == 0)
	{
		struct hostent *he;
		struct sockaddr_in their_addr;
		he = gethostbyname(m_sHostname.c_str());
		if((m_socket = socket(AF_INET,SOCK_STREAM,0))==-1)
		{
			perror("socketi error!");
                        m_bLive = false;
                        m_socket = 0;
			return false;
		}
                if(he == NULL)
                {
                       cerr<<"gethostbyname return NULL "<<endl;
                       return false;
                }

		their_addr.sin_family = AF_INET;
		their_addr.sin_port = htons( m_iPort );
		their_addr.sin_addr = *((struct in_addr *)he->h_addr);
		bzero(&(their_addr.sin_zero), 8);
		if(connect(m_socket, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) ==-1){
			perror("connect error!");
			close(m_socket);
			m_socket = 0;
			m_bLive = false;
			return false;
		}
/**
设置超时是因为，可能由于对方的原因导致此socket处于阻塞状态，从而使得整个netproxy处于阻塞状态！

*/
		struct timeval timeout = {0, 5000};
		setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout,  sizeof(struct timeval));
		setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout,  sizeof(struct timeval));
                int flags = 1;
                setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
                setsockopt( m_socket, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
                struct linger ling = {0, 0};
                setsockopt( m_socket, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
                setsockopt( m_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));

                m_iCounts = 0;
	}  
	m_bLive = true;
	return m_bLive;
}

void SocketConn:: disConnect()
{
	if(m_socket != 0)
	{
		cout<<" close "<< m_sHostname.c_str()<<":"<<m_iPort <<endl;
                close(m_socket);
		m_socket  = 0;
		m_lLasttime = time(NULL);
		m_bLive = false;
	}
	else
		m_bLive = false;
}

bool SocketConn:: ReConnect()
{
	if(m_socket != 0)
	{
                close(m_socket);
		m_socket  = 0;
	}
        return Connect();
}

int SocketConn:: Proxy(const char *data, unsigned dlen, char **wbuf, unsigned &wsize, unsigned &wbytes, bool bReply)
{
	if(m_socket <= 0 ) 
		return -1;
        assert(*wbuf != NULL);       
 
        m_iCounts++;	
        int slen = Nantx_Write(m_socket,(char *) data, dlen);
//      int slen = send(m_socket, data, dlen, 0);
        DEBUG5("send length=", slen, m_sHostname,":", m_iPort);
        if(slen ==-1) {
		DEBUG5("send length=", slen, m_sHostname,":", m_iPort);
		disConnect();
		return -1;
        }
        if(!bReply){
                DEBUG1("needn't reply, so return");
                return 0;
        }
        DEBUG1("Begin to read ... ");
        int readlen = Nantx_Read( m_socket, wbuf, wsize, wbytes, 5); 
        if(readlen > 0)
        {
                DEBUG2("Yes, read length = ", readlen);
                wbytes = readlen;
                return 0;
        }
        DEBUG3("read length = ", readlen, ";  so will disconnect!");
        disConnect();
        return -2;
}
/*
bool SocketConn::getStatus( int imax )
{
        if(m_iCounts >= imax)
             return false;

        if(m_bLive)
           return m_bLive;

        m_lCurtime = time(NULL);
        if(m_lLasttime < ( m_lCurtime - DEAD_CHECK_TIME))
        {
              disConnect();
              Connect();
              m_lLasttime = m_lCurtime;
        }
        return m_bLive;
}
*/
